package com.winning.gjhlht.ihe.hl7ClientService.data.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.sql.Clob;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.quartz.CronTrigger;
import org.quartz.TriggerUtils;

import com.cownew.ctk.common.RandomGUID;
import com.winning.common.Constans;
import com.winning.common.beans.ihe.IHERequestBodyBean;
import com.winning.common.beans.ihe.IHERequestItemBean;
import com.winning.common.beans.xmlTemp.XMLTempBeanManager;
import com.winning.common.beans.xmlTemp.XMLTempConfigBean;
import com.winning.common.data.dao.impl.PlatBasicDataDao;
import com.winning.common.data.service.PlatBasicDataService;
import com.winning.common.tools.XMLTool;
import com.winning.core.net.CXFWebserviceClent;
import com.winning.gjhlht.ihe.hl7ClientService.data.dao.impl.IHEDataDao;
import com.winning.gjhlht.ihe.hl7ClientService.data.dao.inter.IHEDataDaoInter;

public class IHEBaseDataService {

    protected static Logger LOGGER = Logger.getLogger("pbsLoger");

    /**
     * 将XML结构装换为JSON数组，并且列大写
     * 方法名称: paraseXMLToJSONArray
     *
     * @param
     * @return List<Map   <   String   ,   Object>>  返回类型说明<br/>
     * @throws <br/>
     * @author zhaqiang@winning.com.cn<br/>
     * 创建时间：2017-2-28/上午10:03:06<br/>
     */
    protected static JSONArray paraseXMLToJSONArray(String resultXML) {
        //JSON数组
        JSONArray jsonArray = new JSONArray();

        Document messageDocument = XMLTool.getDocumentFromXMLString(resultXML, false);

        Element rootElement = messageDocument.getRootElement();

        List<Element> recordElementList = rootElement.elements();

        //循环遍历所有行
        for (Iterator<Element> recordElementIterator = recordElementList.iterator(); recordElementIterator.hasNext(); ) {
            Element recordElement = (Element) recordElementIterator.next();

            //解析表中一行数据的所有列
            List<Element> paramsElementList = recordElement.elements();

            //存放所有列的值
            HashMap<String, Object> columnObjectMap = new HashMap<String, Object>();

            //解析所有列
            for (Iterator<Element> paramElementIterator = paramsElementList.iterator(); paramElementIterator.hasNext(); ) {
                //列节点
                Element paramElement = (Element) paramElementIterator.next();

                //列名称
                String columnNameStr = paramElement.getName() == null ? "" : paramElement.getName().trim();

                //列的值
                Object valueObject = paramElement.getTextTrim();

                String columnValueStr = "";

                //统一将表字段值转换成String类型处理
                columnValueStr = valueObject == null ? "" : valueObject.toString();

                //列名字转换大写, 为了和配置文件一直
                String upperColumnNameStr = columnNameStr.toUpperCase();

                //存放业务数据值，KEY 为数据库列名称
                columnObjectMap.put(upperColumnNameStr, columnValueStr);

            }

            if (columnObjectMap != null) {
                JSONObject jsonObject = new JSONObject();
                jsonObject = JSONObject.fromObject(columnObjectMap);
                jsonArray.add(jsonObject);
            }
        }

        return jsonArray;
    }


    /**
     * 将CDA文档内容转为BASE64格式的字符串
     * 方法名称: getBASE64
     *
     * @param cdaContentValue CDA文档中的内容
     * @return String  返回类型说明
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2017-1-12/下午4:55:25<br/>
     */
    @SuppressWarnings("restriction")
    public static String getBASE64(String cdaContentValue) {

        try {
            String base64Str = "";

            if (cdaContentValue == null) {
                return null;
            }

            try {

                base64Str = (new sun.misc.BASE64Encoder()).encode(cdaContentValue.getBytes("UTF-8")).replace("\n", "").replace("\r", "");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            return base64Str;
        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        }

        return null;
    }


    /**
     * 将CLOB类型转换为字符串类型
     * 方法名称: ClobToString
     *
     * @param
     * @return String  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-2-9/下午1:25:46<br/>
     */
    protected static String ClobToString(Clob clob) {
        String reString = "";
        Reader is = null;
        BufferedReader br = null;
        try {
            is = clob.getCharacterStream();
            br = new BufferedReader(is);
            String s = br.readLine();
            StringBuffer sb = new StringBuffer();
            while (s != null) {
                sb.append(s);
                s = br.readLine();
            }
            reString = sb.toString();
        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        } finally {
            try {
                is.close();
                br.close();
            } catch (IOException e) {
                LOGGER.error(e, e.fillInStackTrace());
                e.printStackTrace();
            }
        }

        return reString;
    }


    /**
     * 根据serviceID获取定时配置对象
     * 方法名称: getServiceConfigBeanBy
     *
     * @param
     * @return XMLTempConfigBean  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-2-7/上午11:03:30<br/>
     */
    public XMLTempConfigBean getServiceConfigBeanBy(String serviceID) {
        //获取配置信息
        Map<String, XMLTempConfigBean> XMLTempConfigBeanMap = XMLTempBeanManager.getInstance().getXMLTempConfigBeanMap();

        //获取数据源
        for (Entry<String, XMLTempConfigBean> entity : XMLTempConfigBeanMap.entrySet()) {
            //一个模板接口配置任务
            XMLTempConfigBean xmlTempConfigBean = entity.getValue();

            //获取个人信息注册数据源
            if (xmlTempConfigBean.getServiceID().equals(serviceID)) {
                return xmlTempConfigBean;
            }
        }

        return null;
    }


    /**
     * 获取配置模板信息 <br/>
     * 方法名称: getIHERequestBodyBeanHandler
     *
     * @param
     * @return IHERequestBodyBean  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-13/上午11:20:51<br/>
     */
    protected IHERequestBodyBean getIHERequestBodyBeanHandler(String xmFilelTempPath) {
        Document document = XMLTool.getXMLDocument(xmFilelTempPath);

        //IHE请求消息模板实体对象
        IHERequestBodyBean iheRequestBodyBean = new IHERequestBodyBean();

        if (document != null) {
            Element rootElment = document.getRootElement();
            Element requestBodyElment = rootElment.element(Constans.REQUEST_BODY_ATTRIBUTE);

            //对应请求消息XML文件地址
            Attribute requestMessageFilePathAttr = requestBodyElment.attribute(Constans.REQUEST_MESSAGE_FILE_PATH_ATTRIBUTE);
            if (requestMessageFilePathAttr != null) {
                String requestMessageFilePathValue = requestMessageFilePathAttr.getStringValue();
                iheRequestBodyBean.setRequestMessageFilePath(requestMessageFilePathValue);
            }

            //查询业务数据的sql
            Attribute sqlValueAttr = requestBodyElment.attribute(Constans.SQL_VALUE_ATTRIBUTE);
            if (sqlValueAttr != null) {
                String sqlValue = sqlValueAttr.getStringValue();
                iheRequestBodyBean.setSqlValue(sqlValue);
            }

            //webservice开发的接口方法名称
            Attribute webserviceMethodNameAttr = requestBodyElment.attribute(Constans.WEBSERVICE_METHOD_NAME_ATTRIBUTE);
            if (webserviceMethodNameAttr != null) {
                String webserviceMethodNameValue = webserviceMethodNameAttr.getStringValue();
                iheRequestBodyBean.setWebserviceMethodName(webserviceMethodNameValue);
            }

            //webservcie服务地址，指向到具体的wsdl
            Attribute webserviceURLAttr = requestBodyElment.attribute(Constans.WEBSERVICE_URL_ATTRIBUTE);
            if (webserviceURLAttr != null) {
                String webserviceURLValue = webserviceURLAttr.getStringValue();
                iheRequestBodyBean.setWebserviceURL(webserviceURLValue);
            }

            //是否调用审计接口，共享文档注册需要调用
            Attribute isAuditAttr = requestBodyElment.attribute(Constans.IS_AUDIT_ATTRIBUTE);
            if (isAuditAttr != null) {
                String isAuditValue = isAuditAttr.getStringValue();

                if ("true".equals(isAuditValue)) {
                    iheRequestBodyBean.setAudit(true);
                } else {
                    iheRequestBodyBean.setAudit(false);
                }
            }

            //审计接口webservcie服务地址，指向到具体的wsdl
            Attribute auditWebserviceURLAttr = requestBodyElment.attribute(Constans.AUDIT_WEBSERVICE_URL_ATTRIBUTE);
            if (auditWebserviceURLAttr != null) {
                String auditWebserviceURLValue = auditWebserviceURLAttr.getStringValue();
                iheRequestBodyBean.setAuditWebserviceURL(auditWebserviceURLValue);
            }

            //平台webservice接口服务名称
            Attribute actionMethodNameAttr = requestBodyElment.attribute(Constans.ACTION_METHOD_NAME_ATTRIBUTE);
            if (actionMethodNameAttr != null) {
                String actionMethodNameValue = actionMethodNameAttr.getStringValue();
                iheRequestBodyBean.setActionMethodName(actionMethodNameValue);
            }

            //IHE消息响应结果处理class
            Attribute responseClassAttr = requestBodyElment.attribute(Constans.RESPONSE_CLASS_ATTRIBUTE);
            if (responseClassAttr != null) {
                String responseClassValue = responseClassAttr.getStringValue();
                iheRequestBodyBean.setResponseClass(responseClassValue);
            }

            //明细列表
            List<IHERequestItemBean> iheRequestItemList = new ArrayList<IHERequestItemBean>();

            //获取详情列表
            for (Iterator<Element> iterator = requestBodyElment.elementIterator(); iterator.hasNext(); ) {
                IHERequestItemBean iheRequestItemBean = new IHERequestItemBean();

                Element childElement = iterator.next();

                Attribute xPathValueAttr = childElement.attribute(Constans.X_PATH_VALUE_ATTRIBUTE);
                if (xPathValueAttr != null) {
                    String xPathValue = xPathValueAttr.getStringValue();
                    iheRequestItemBean.setxPathValue(xPathValue);
                }

                // xpath指向的xml结构的类型,大小写不区分，统一为大写
                Attribute xPathTypeAttr = childElement.attribute(Constans.X_PATH_TYPE_ATTRIBUTE);
                if (xPathTypeAttr != null) {
                    String xPathType = xPathTypeAttr.getStringValue() == null ? "" : xPathTypeAttr.getStringValue().toUpperCase();
                    if (Constans.XML_ELEMENT_TYPE.equals(xPathType)) {
                        iheRequestItemBean.setxPathType(Constans.XML_ELEMENT_TYPE);
                    } else {
                        iheRequestItemBean.setxPathType(Constans.XML_ATTRIBUTE_TYPE);
                    }
                }

                Attribute localColumnNameAttr = childElement.attribute(Constans.LOCAL_COLUMN_NAME_ATTRIBUTE);
                if (localColumnNameAttr != null) {
                    String localColumnName = localColumnNameAttr.getStringValue() == null ? "" : localColumnNameAttr.getStringValue().toUpperCase();
                    iheRequestItemBean.setLocalColumnName(localColumnName);
                }

                //默认值
                Attribute defaultValueAttr = childElement.attribute(Constans.DEFAULT_VALUE_ATTRIBUTE);
                if (defaultValueAttr != null) {
                    String defaultValue = defaultValueAttr.getStringValue() == null ? "" : defaultValueAttr.getStringValue().toUpperCase();
                    iheRequestItemBean.setDefaultValue(defaultValue);
                }

                //数据类型,大小写不区分, 统一为大写
                Attribute dataTypeAttr = childElement.attribute(Constans.DATA_TYPE_ATTRIBUTE);
                if (dataTypeAttr != null) {
                    String dataType = dataTypeAttr.getStringValue() == null ? "" : dataTypeAttr.getStringValue().toUpperCase();
                    if (Constans.DATE_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.DATE_TYPE);
                    } else if (Constans.GUID_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.GUID_TYPE);
                    } else if (Constans.CLOB_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.CLOB_TYPE);
                    } else if (Constans.XML_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.XML_TYPE);
                    } else {
                        iheRequestItemBean.setDataType(Constans.STRING_TYPE);
                    }
                }

                //大小写区分
                Attribute dataFormatterAttr = childElement.attribute(Constans.DATA_FORMATTER_ATTRIBUTE);
                if (dataFormatterAttr != null) {
                    String dataFormatter = dataFormatterAttr.getStringValue();
                    iheRequestItemBean.setDataFormatter(dataFormatter);
                }

                iheRequestItemList.add(iheRequestItemBean);
            }

            //保存所有配置明细列表
            iheRequestBodyBean.setIheRequestItemList(iheRequestItemList);
        }

        return iheRequestBodyBean;
    }

    /**
     * 创建一个注册请求的XML信息 <br/>
     * 方法名称: createOneRegistrationXMLInfoHandler
     *
     * @param
     * @return Document  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-13/上午9:46:17<br/>
     */
    protected Document createOneRegistrationXMLInfoHandler(Document xmlDoc, Map<String, Object> patientPersionInfoMap, IHERequestBodyBean iheRequestBodyBean) {
        List<IHERequestItemBean> iheRequestItemList = iheRequestBodyBean.getIheRequestItemList();

        for (Iterator<IHERequestItemBean> IHERequestItemBeanIterator = iheRequestItemList.iterator(); IHERequestItemBeanIterator.hasNext(); ) {
            IHERequestItemBean iheRequestItemBean = IHERequestItemBeanIterator.next();

            String xPathTypeValue = iheRequestItemBean.getxPathType();

            String xPathValue = iheRequestItemBean.getxPathValue();

            //数据类型
            String dataTypeValue = iheRequestItemBean.getDataType();

            //格式化字符串
            String dateFormatterValue = iheRequestItemBean.getDataFormatter();

            //获取本地业务表列名称，从业务表结果集总获取数据
            String columnName = iheRequestItemBean.getLocalColumnName();

            String columnValue = "";

            //如果columnName为{GUID}表达式，则为随机数生成GUID
            if (Constans.GUID_TYPE.equals(dataTypeValue)) {
                //自动生成唯一主键
                columnValue = new RandomGUID().toString();
            } else if (Constans.DATE_TYPE.equals(dataTypeValue)) {
                //时间类型，数据库统一为标准格式：YYYY-MM-DD hh:mm:ss; 再按照配置的时间格式转换

            }
            //处理xml数据，转换成系统需要的base64编码
            else if (Constans.XML_TYPE.equals(dataTypeValue)) {
                Clob clob = (Clob) patientPersionInfoMap.get(columnName);
                String value = ClobToString(clob);

                //转base64编码
                columnValue = getBASE64(value);

                LOGGER.debug("--> 生成好的Base64编码:" + columnValue);

            } else {
                columnValue = (String) patientPersionInfoMap.get(columnName);

            }

            //如果数据库返回结果为空的处理, 需要判断是否提供默认值设置
            if (columnValue == null || columnValue.length() == 0) {
                //如果提供了默认值，则设置默认值
                if (iheRequestItemBean.getDefaultValue() != null && !"".equals(iheRequestItemBean.getDefaultValue())) {
                    columnValue = iheRequestItemBean.getDefaultValue();
                } else {
                    columnValue = "";
                }
            }

            //如果配置的xpath路径是获取元素节点对象，则直接给xml元素节点文本赋值<test>...</test>
            if (Constans.XML_ELEMENT_TYPE.equals(xPathTypeValue)) {
                Element xpathElement = XMLTool.selectElementObjByXPath(xmlDoc, xPathValue);


                if (xpathElement != null) {
                    //给xml元素节点文本赋值
                    xpathElement.setText(columnValue);
                }
            }
            //如果配置的xpath路径是获取属性对象，则直接给属性对象赋值<test value="...">...</test>
            else if (Constans.XML_ATTRIBUTE_TYPE.equals(xPathTypeValue)) {
                Attribute attribute = XMLTool.selectAttributeObjectByXPath(xmlDoc, xPathValue);

                if (attribute != null) {
                    //给xml元素节点中的属性赋值
                    attribute.setValue(columnValue);
                }
            }
        }

        return xmlDoc;
    }


    /**
     * 根据定时器表达是获取下次生成时间
     * 方法名称: getTimeByTrigger
     *
     * @param
     * @return String  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-2-7/下午5:05:22<br/>
     */
    protected String getTimeByTrigger(String serviceID) {
        try {
            //获取下次定时上传执行时间
            XMLTempConfigBean xmlTempConfigBean = getServiceConfigBeanBy(serviceID);
            if (xmlTempConfigBean != null) {
                String time = xmlTempConfigBean.getJobExpressionValue();

                CronTrigger cronTriggerImpl = new CronTrigger();
                cronTriggerImpl.setCronExpression(time);//这里写要准备猜测的cron表达式

                Date now = new Date();

                //这个是重点，一行代码搞定~~
                List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, now.getDate());

                //System.out.println(dates.size());
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if (dates != null && dates.size() != 0) {
                    return dateFormat.format(dates.get(0));

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 上传一份互联互通服务消息
     * 方法名称: uploadHlhtService
     *
     * @param
     * @return boolean  返回类型说明<br/>
     * @throws <br/>
     * @author zhaqiang@winning.com.cn<br/>
     * 创建时间：2017-2-28/下午2:33:32<br/>
     */
    protected boolean uploadHlhtService(String tjSQL, String SID, PlatBasicDataService platBasicDataService, IHEDataDaoInter iheDataDao) {
        try {
            //健康档案上传配置信息
            XMLTempConfigBean xmlTempConfigBean = getServiceConfigBeanBy(SID);

            //xml配置模板的地址
            String tempFilePath = xmlTempConfigBean.getXmlTempFilePath();

            //初始化过程中，解析模板配置信息,每次任务启动时，执行, 模板配置文件中包含：消息XML的文件地址和具体节点的关联参数
            IHERequestBodyBean iheRequestBodyBean = getIHERequestBodyBeanHandler(tempFilePath);

            String serviceID = xmlTempConfigBean.getServiceID();

            String serviceName = xmlTempConfigBean.getServiceName();

            String basicSQL = iheRequestBodyBean.getSqlValue();

            //添加查询条件
            basicSQL += tjSQL;

            LOGGER.info("--> 一个上传服务查询SQL:" + basicSQL);

            List<HashMap<String, Object>> list = iheDataDao.executeSQLByDataSourseID(basicSQL, null, xmlTempConfigBean.getDbDataSourseID());

            if (list != null && list.size() > 0) {
                //一个请求的基本信息, key值为表字段名称，统一为大写
                Map<String, Object> registrationRequestInfoMap = list.get(0);

                if (registrationRequestInfoMap != null) {
                    //配置的IHE请求消息xml文件地址, 目标XML结构文件
                    String iheMessageFilePath = iheRequestBodyBean.getRequestMessageFilePath();

                    //获取IHE请求消息XML可操作对象
                    Document documentSource = XMLTool.getXMLDocument(iheMessageFilePath);

                    String xmlStr = documentSource.asXML() == null ? "" : documentSource.asXML();

                    xmlStr = xmlStr.substring(39, xmlStr.length());

                    //生成一个请求的IHE入参xml模板对象
                    Document xmlDoc = XMLTool.getDocumentFromXMLString(xmlStr, true);


                    xmlDoc = createOneRegistrationXMLInfoHandler(xmlDoc, registrationRequestInfoMap, iheRequestBodyBean);

                    String requestXMLValue = xmlDoc.asXML();

                    String requestXMLMessage = requestXMLValue.substring(39, requestXMLValue.length());

                    LOGGER.info("--> 一条请求消息XML结构:" + requestXMLMessage);

                    //调用互联互通服务,采用的是CXF框架
                    CXFWebserviceClent.sendCXFWebserviceRequestHandler(documentSource, platBasicDataService, iheRequestBodyBean, requestXMLMessage, registrationRequestInfoMap, xmlTempConfigBean);


                    return true;
                }
            }
        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        }

        return false;
    }

    /**
     * 根据上传服务ID获取数据源
     * 方法名称: getDBDataSouorceID
     *
     * @param
     * @return String  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-2-7/上午10:51:45<br/>
     */
    protected String getDBDataSouorceID(String serviceID) {
        String dbDataSourceID = "";
        //获取配置信息
        Map<String, XMLTempConfigBean> XMLTempConfigBeanMap = XMLTempBeanManager.getInstance().getXMLTempConfigBeanMap();

        //获取数据源
        for (Entry<String, XMLTempConfigBean> entity : XMLTempConfigBeanMap.entrySet()) {
            //一个模板接口配置任务
            XMLTempConfigBean xmlTempConfigBean = entity.getValue();

            //获取个人信息注册数据源
            if (xmlTempConfigBean.getServiceID().equals(serviceID)) {
                dbDataSourceID = xmlTempConfigBean.getDbDataSourseID();

                break;
            }
        }

        return dbDataSourceID;
    }
}
